require 'generator/generator'

class Variable
  attr_accessor :scope, :name, :var_type, :addr_base, :addr_offset, :is_array, :size, :is_reference
  def initialize(scope, name, var_type, addr_base="Reg[FP]", addr_offset=0, is_array=false, size=1)
    @scope = scope
    @name = name
    @var_type = var_type
    @addr_base = addr_base
    @addr_offset = addr_offset
    @is_array = is_array
    @size = size
    @is_reference = false
    @calculated_address = nil
  end
  
  def allocate
    suffix = ""
    if(@is_array)
      suffix = "..#{@addr_offset + @size - 1}"
    end
    Generator.write_line("Reg[SP] = Reg[SP] + #{size};", "Allocate FP + #{@addr_offset}#{suffix} for #{name}")
  end
  
  def load(reg, indexed=false, index_reg=0)
    if(@is_reference)
      # Indirect
      load_indirect(reg, indexed, index_reg)
    else
      # Direct
      load_direct(reg, indexed, index_reg)
    end
  end
  
  def load_address(reg, indexed=false, index_reg=0)
    if(@is_reference)
      # Indirect
      load_indirect(reg, indexed, index_reg, true)
    else
      # Direct
      load_direct(reg, indexed, index_reg, true)
    end
  end
  
  def load_direct(reg, indexed, index_reg, load_address=false)
    if(indexed)
      # Direct Array
      inst = "Reg[ACC] = #{@addr_base} + Reg[#{index_reg}];"
      comment = "index into the '#{@name}' array"
      Generator.write_line(inst, comment)
      addr = "Reg[ACC]"
    else
      addr = "#{@addr_base}"
    end
    if(load_address)
      inst = "Reg[#{reg}] = #{addr} + #{@addr_offset};"
      comment = "Load address of #{@var_type} variable #{@name}"
    else
      inst = "Reg[#{reg}] = MEM[#{addr} + #{@addr_offset}];"
      comment = "Load #{@var_type} variable #{@name}"
    end
    Generator.write_line(inst, comment)
  end
  
  def load_indirect(reg, indexed, index_reg, load_address=false)
    inst = "Reg[ACC] = MEM[#{@addr_base} + #{@addr_offset}];"
    comment = "Load the address of variable #{@name}"
    Generator.write_line(inst, comment)
    if(indexed)
      # Indirect Array
      inst = "Reg[ACC] = Reg[ACC] + Reg[#{index_reg}];"
      comment = "index into the '#{@name}' array"
      Generator.write_line(inst, comment)
    end
    if(load_address)
      inst = "Reg[#{reg}] = Reg[ACC];"
      comment = "Load indirect address of #{@var_type} variable #{@name}"
    else
      inst = "Reg[#{reg}] = MEM[Reg[ACC]];"
      comment = "Load indirect #{@var_type} variable #{@name}"
    end
    Generator.write_line(inst, comment)
  end

  def store(reg, indexed=false, index_reg=0)
    if(@is_reference)
      # Indirection
      store_indirect(reg, indexed, index_reg)
    else
      # No Indirection
      store_direct(reg, indexed, index_reg)
    end
  end
  
  def store_direct(reg, indexed, index_reg)
    if(indexed)
      # Direct Array
      inst = "Reg[#{index_reg}] = #{@addr_base} + Reg[#{index_reg}];"
      comment = "index into the '#{@name}' array"
      Generator.write_line(inst, comment)
      addr = "Reg[#{index_reg}]"
    else
      addr = "#{@addr_base}"
    end
    addr << " + #{@addr_offset}" if @addr_offset != 0
    inst = "MEM[#{addr}] = Reg[#{reg}];"
    comment = "Store #{@var_type} variable #{@name}"
    Generator.write_line(inst, comment)
  end

  def store_indirect(reg, indexed, index_reg)
    inst = "Reg[ACC] = MEM[#{@addr_base} + #{@addr_offset}];"
    comment = "Load the address of variable #{@name}"
    Generator.write_line(inst, comment)
    if(indexed)
      # Indirect Array
      inst = "Reg[ACC] = Reg[ACC] + Reg[#{index_reg}];"
      comment = "index into the '#{@name}' array"
      Generator.write_line(inst, comment)
    end
    inst = "MEM[Reg[ACC]] = Reg[#{reg}];"
    comment = "Store #{@var_type} variable #{@name}"
    Generator.write_line(inst, comment)
  end  
end